package com.citycloud.ccuap.tc.admin.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.util.AntPathMatcher;

import com.citycloud.ccuap.framework.util.DateUtil;
import com.citycloud.ccuap.tc.admin.constant.AdminConstant;
import com.citycloud.ccuap.tc.admin.entity.OauthClientDetails;
import com.citycloud.ccuap.tc.admin.feignclient.CheckTokenInfo;
import com.citycloud.ccuap.tc.admin.feignclient.OAuth2FCService;
import com.citycloud.ccuap.tc.admin.repository.OauthClientDetailsRepository;
import com.citycloud.ccuap.tc.admin.utils.WebUtils;

import lombok.extern.slf4j.Slf4j;

/***
 * @className ClientFilter
 * @author wangyj
 * @Date 2019/12/4 18:53
 * @description
 */
@Order(-99)
@Slf4j
@WebFilter(filterName = "clientFilter", urlPatterns = { "/v1/sys/user4sec/*", "/v1/sys/user/permission/*","/v1/sys/datac/*"})
public class ClientFilter implements Filter {

	private static List<String> excludeUrls = new ArrayList<>();

//	@Value("${interface.expiration.time:10}")
//	private long interfaceCllTtl;

	private static String TOKEN = "token";
	private static String ACCESS_TOKEN = "access_token";

//	@Autowired
//	private RestOperations restTemplate;

	@Autowired
	private OAuth2FCService oauth2Service;

//	@Autowired
//	private SecurityConfig.SecurityOauth2ResourceConfig securityOauth2ResourceConfig;

	@Autowired
	OauthClientDetailsRepository oauthClientDetailsRepository;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		excludeUrls.add("/v1/sys/user4sec/rebuildSynCache");
		excludeUrls.add("/v1/sys/user4sec/buildCache");
		excludeUrls.add("/v1/sys/user4sec/testInterface");
		excludeUrls.add("/v1/sys/user4sec/getServerTime");
		excludeUrls.add("/v1/sys/user4sec/getAllSysProjects");
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		// 将请求转换成HttpServletRequest 请求
		HttpServletRequest req = (HttpServletRequest) servletRequest;
		AntPathMatcher matcher = new AntPathMatcher();
		boolean flag = false;
		String uri = req.getRequestURI();
		if (uri.startsWith(req.getContextPath())) {
			uri = uri.replaceFirst(req.getContextPath(), "");
		}
		for (String excludeUrl : excludeUrls) {
			flag = matcher.match(excludeUrl, uri);
			if (flag) {
				break;
			}
		}
		if (flag) {
			filterChain.doFilter(servletRequest, servletResponse);
		} else {
			String accessToken = StringUtils.isEmpty(req.getParameter(TOKEN)) ? req.getParameter(ACCESS_TOKEN)
					: req.getParameter(TOKEN);
			if (StringUtils.isEmpty(accessToken)) {
				accessToken = StringUtils.isEmpty(req.getHeader(TOKEN)) ? req.getHeader(ACCESS_TOKEN)
						: req.getHeader(TOKEN);
			}
			if (StringUtils.isNotBlank(accessToken)) {
				/*
				 * HttpHeaders headers = new HttpHeaders(); // checkToken if
				 * (headers.getContentType() == null) {
				 * headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); } String creds
				 * = String.format("%s:%s", securityOauth2ClientConfig.getClientId(),
				 * securityOauth2ClientConfig.getClientSecret());
				 * headers.set("Authorization","Basic " + new
				 * String(Base64.encode(creds.getBytes("UTF-8"))));
				 */
				try {
					CheckTokenInfo checkTokenInfo = oauth2Service.checkToken(accessToken);
					if (!checkTokenInfo.getActive()) {
						WebUtils.putResponse(servletResponse, AdminConstant.ACCESS_TOKEN_VAILD, 401L);
						return;
					}
				} catch (Exception e) {
					WebUtils.putResponse(servletResponse, AdminConstant.ACCESS_TOKEN_VAILD, 401L);
					return;
				}

				filterChain.doFilter(servletRequest, servletResponse);
				return;
			}

//			String clientId = req.getParameter("AccessKeyId");
//			String sign = req.getParameter("signature");
//			String timestamp = req.getParameter("timeStamp");
//			if (StringUtils.isBlank(clientId)) {
//				logger(req, "失败原因：请求clientId为空！");
//				WebUtils.putResponse(servletResponse, AdminConstant.APPID_NOT_EXISTS, 401L);
//				return;
//			}
//
//			if (StringUtils.isBlank(sign)) {
//				logger(req, "失败原因：未设定签名参数：signature");
//				WebUtils.putResponse(servletResponse, AdminConstant.VALID_SIGNATURE, 401L);
//				return;
//			}
//
//			if (StringUtils.isEmpty(timestamp)) {
//				logger(req, "失败原因：未设定时间戳参数：timeStamp");
//				WebUtils.putResponse(servletResponse, AdminConstant.VALID_TIMESTAMP, 401L);
//				return;
//			}
//
////            if (Long.parseLong(timestamp) > System.currentTimeMillis() || (System.currentTimeMillis() - Long.parseLong(timestamp) > interfaceCllTtl * 1000L)) {
////                WebUtils.putResponse(servletResponse,TCConstant.VALID_TIMESTAMP,401L);
////                return;
////            }
//
//			OauthClientDetails oauthClientDetails = oauthClientDetailsRepository.findByClientId(clientId);
//
//			if (null == oauthClientDetails) {
//				logger(req, "失败原因：系统中未查询到应用ID：" + clientId);
//				WebUtils.putResponse(servletResponse, AdminConstant.APPID_NOT_EXISTS, 401L);
//				return;
//			}
//
//			if (!checkSignature(oauthClientDetails.getSecret(), servletRequest)) {
//				WebUtils.putResponse(servletResponse, AdminConstant.VALID_SIGNATURE, 401L);
//				return;
//			}
			filterChain.doFilter(servletRequest, servletResponse);
		}

	}

	/**
	 * 签名比较
	 *
	 * @param accessKeySecret app秘钥
	 * @param request         请求
	 * @return 附加参数
	 */
	private boolean checkSignature(String accessKeySecret, ServletRequest request) {

		String key = "params=";
		List<String> paramKeys = new ArrayList<>();

		Map<String, String[]> params = request.getParameterMap();
		paramKeys.add("AccessKeySecret");

		for (Map.Entry<String, String[]> entry : params.entrySet()) {
			if (!"signature".equals(entry.getKey())) {
				paramKeys.add(entry.getKey());
			}
		}
		paramKeys.sort(String.CASE_INSENSITIVE_ORDER);
		String paramValues;
		for (String paramKey : paramKeys) {
			if ("AccessKeySecret".equals(paramKey)) {
				key = key + paramKey + "=" + (StringUtils.isNotBlank(accessKeySecret) ? accessKeySecret : "") + "&";
			} else if (null != params.get(paramKey) && params.size() > 0) {
				paramValues = Arrays.asList(params.get(paramKey)).toString();
				key = key + paramKey + "=" + paramValues.substring(1, paramValues.length() - 1) + "&";
			} else {
				key = key + paramKey + "=&";
			}
		}

		if (key.endsWith(AdminConstant.STR_QUESTION_AMPERSEND)) {
			key = key.substring(0, key.length() - 1);
		}

		String sign = request.getParameter("signature");

		String md5Value = DigestUtils.md5Hex(key);
		boolean returnFlag = md5Value.equals(sign);
		if (returnFlag) {
			logger((HttpServletRequest) request, "请求成功: 签名参数：sign:" + sign + ",签名拼接串：" + key + ",md5值：" + md5Value);
		} else {
			logger((HttpServletRequest) request, "请求失败: 签名参数：sign:" + sign + ",签名拼接串：" + key + ",md5值：" + md5Value);
		}
		return returnFlag;
	}

	private void logger(HttpServletRequest req, String content) {
		StringBuffer sb = new StringBuffer("");
		Map<String, String[]> params = req.getParameterMap();
		String paramValues = "";

		for (Map.Entry<String, String[]> entry : params.entrySet()) {
			sb.append(entry.getKey()).append("=");
			if (null != params.get(entry.getKey()) && params.size() > 0) {
				paramValues = Arrays.asList(params.get(entry.getKey())).toString();
				sb.append(paramValues.substring(1, paramValues.length() - 1)).append("&");
			}
		}
		if (sb.toString().endsWith(AdminConstant.STR_QUESTION_AMPERSEND)) {
			paramValues = sb.toString().substring(0, sb.toString().length() - 1);
		}
		log.debug(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss") + "发起后端接口请求" + req.getRequestURI() + ",参数："
				+ paramValues + "," + content);
	}

}
